import { BlockInputEvents, Camera, EventTouch, Layers, Node, NodeEventType, warn, Widget } from "cc";
import { LayerDialog } from "./gui/LayerDialog";
import { LayerNotify } from "./gui/LayerNotify";
import { LayerPopUp } from "./gui/LayerPopup";
import { LayerUI } from "./gui/LayerUI";
import { UICallbacks } from "./gui/Defines";
import { UIID } from "../config/GameUIConfig";
import { sleep } from "../utils/Util";
import { ResLoader } from "./ResLoader";
import { Prefab } from "cc";
import { instantiate } from "cc";
import { isValid } from "cc";

/** 界面层类型 */
export enum LayerType {
    /** 主界面层 */
    UI = "LayerUI",
    /** 弹窗层 */
    PopUp = "LayerPopUp",
    /** 系统触发模式窗口层 */
    System = "LayerSystem",
    /** 滚动消息提示层 */
    Notify = "LayerNotify",
    /** 新手引导层 */
    Guide = "LayerGuide",
    /** 点击层 */
    Click = "ClickGuide"
}

/** 
 * 界面配置结构体
 * @example
// 界面唯一标识
export enum UIID {
    Loading = 1,
    Window,
    Netinstable
}

// 打开界面方式的配置数据
export var UIConfigData: { [key: number]: UIConfig } = {
    [UIID.Loading]: { layer: LayerType.UI, prefab: "loading/prefab/loading", bundle: "resources" },
    [UIID.Netinstable]: { layer: LayerType.PopUp, prefab: "common/prefab/netinstable" },
    [UIID.Window]: { layer: LayerType.Dialog, prefab: "common/prefab/window" }
}
 */
export interface UIConfig {
    /** -----公共属性----- */
    /** uid */
    uid: UIID
    /** 远程包名 */
    bundle?: string;
    /** 窗口层级 */
    layer: LayerType;
    /** 预制资源相对路径 */
    prefab: string;
    /** 是否自动施放,默认释放 */
    destroy?: boolean;
}

/** 界面层级管理器 */
export class LayerManager {
    /** 界面根节点 */
    root!: Node;
    /** 界面摄像机 */
    camera!: Camera;
    /** 新手引导层 */
    guide!: Node;
    /** 点击层 */
    click!: Node;

    /** 界面层 */
    private ui!: LayerUI;
    /** 弹窗层 */
    private popup!: LayerPopUp;
    /** 游戏系统提示弹窗  */
    private system!: LayerDialog;
    /** 消息提示控制器，请使用show方法来显示 */
    private notify!: LayerNotify;
    /** UI配置 */
    private configs: { [key: number]: UIConfig } = {};

    static Ins: LayerManager = null

    /** 初始化所有UI的配置对象
     * @param configs 配置对象
     */
    init(configs: { [key: number]: UIConfig }, ins: LayerManager): void {
        this.configs = configs;
        LayerManager.Ins = ins
    }

    /** 渐隐飘过提示
     * @param content 文本表示
     * @example 
     * LayerManager.Ins.toast("提示内容");
     */
    toast(content: string) {
        this.notify.toast(content)
    }

    // /** 打开等待提示 */
    // waitOpen() {
    //     this.notify.waitOpen();
    // }

    // /** 关闭等待提示 */
    // waitClose() {
    //     this.notify.waitClose();
    // }

    /** 同步打开一个窗口
     * @param uiId          窗口唯一编号
     * @param uiArgs        窗口参数
     * @param callbacks     回调对象
     * @example
        LayerManager.Ins.openAsync(UIID.SelectSkillPop, null, {
            onAdded: (node: Node, params: any) => { },
            onRemoved: (node: Node | null, params: any) => { },
            onBeforeRemove: (node: Node, next: Function) => { }
        })
     */
    private open(uiId: UIID, uiArgs: any = null, callbacks?: UICallbacks): void {
        var config = this.configs[uiId];
        if (config == null) {
            warn(`打开编号为【${uiId}】的界面失败，配置信息不存在`);
            return;
        }

        switch (config.layer) {
            case LayerType.UI:
                this.ui.add(config, uiArgs, callbacks);
                break;
            case LayerType.PopUp:
                this.popup.add(config, uiArgs, callbacks);
                break;
            case LayerType.System:
                this.system.add(config, uiArgs, callbacks);
                break;
        }
    }

    /** 异步打开一个窗口
     * @param uiId          窗口唯一编号
     * @param uiArgs        窗口参数
     * @example 
     * var node = await LayerManager.Ins.openAsync(UIID.Loading);
     */
    async openAsync(uiId: number, uiArgs: any = null): Promise<Node | null> {
        return new Promise<Node | null>((resolve, reject) => {
            var callbacks: UICallbacks = {
                onAdded: (node: Node, params: any) => {
                    resolve(node)
                }
            };
            this.open(uiId, uiArgs, callbacks);
        });
    }

    /** 场景替换
     * @param removeUiId  移除场景编号
     * @param openUiId    新打开场景编号
     * @param uiArgs      新打开场景参数
     */
    private replace(removeUiId: number, openUiId: number, uiArgs: any = null) {
        this.open(openUiId, uiArgs);
        this.remove(removeUiId);
    }

    /** 异步场景替换
     * @param removeUiId  移除场景编号
     * @param openUiId    新打开场景编号
     * @param uiArgs      新打开场景参数
     */
    replaceAsync(removeUiId: number, openUiId: number, uiArgs: any = null): Promise<Node | null> {
        return new Promise<Node | null>(async (resolve, reject) => {
            var node = await this.openAsync(openUiId, uiArgs);
            this.remove(removeUiId);
            resolve(node);
        });
    }

    /** 移除指定标识的窗口
     * @param uiId         窗口唯一标识
     * @param isDestroy    移除后是否释放
     * @example
     * LayerManager.Ins.remove(UIID.Loading);
     */
    remove(uiId: number, isDestroy?: boolean) {
        var config = this.configs[uiId];
        if (config == null) {
            warn(`删除编号为【${uiId}】的界面失败，配置信息不存在`);
            return;
        }

        switch (config.layer) {
            case LayerType.UI:
                this.ui.remove(config.prefab, isDestroy);
                break;
            case LayerType.PopUp:
                this.popup.remove(config.prefab, isDestroy);
                break;
            case LayerType.System:
                this.system.remove(config.prefab, isDestroy);
                break;
        }
    }

    /** 构造函数
     * @param root  界面根节点
     */
    constructor(root: Node) {
        this.root = root;
        this.camera = this.root.parent.getComponentInChildren(Camera)!;

        this.ui = new LayerUI(LayerType.UI);
        this.popup = new LayerPopUp(LayerType.PopUp);
        this.system = new LayerDialog(LayerType.System);
        this.notify = new LayerNotify(LayerType.Notify);

        this.guide = this.create_node(LayerType.Guide);

        root.addChild(this.ui);
        root.addChild(this.popup);
        root.addChild(this.system);
        root.addChild(this.notify);
        root.addChild(this.guide);
        this.initClickLayer()
    }

    private create_node(name: string) {
        var node = new Node(name);
        node.layer = Layers.Enum.UI_2D;
        var w: Widget = node.addComponent(Widget);
        w.isAlignLeft = w.isAlignRight = w.isAlignTop = w.isAlignBottom = true;
        w.left = w.right = w.top = w.bottom = 0;
        w.alignMode = 2;
        w.enabled = true;
        return node;
    }

    /** 全局点击事件间隔 */
    private initClickLayer() {
        this.click = this.create_node(LayerType.Click);
        this.root.addChild(this.click);

        const ib = this.create_node('inputBlock')
        ib.parent = this.click
        ib.active = false
        ib.addComponent(BlockInputEvents)
        this.click.on(NodeEventType.TOUCH_START, (event: EventTouch) => {
            event.preventSwallow = true
            if (!ib.active) {
                ib.active = true
                sleep(40).then(() => ib.active = false)
            }
        })
        this.click.on(NodeEventType.TOUCH_MOVE, (event: EventTouch) => event.preventSwallow = true)
        this.click.on(NodeEventType.TOUCH_END, (event: EventTouch) => event.preventSwallow = true)
        this.click.on(NodeEventType.TOUCH_CANCEL, (event: EventTouch) => event.preventSwallow = true)
    }

    clearAllPop(isDestroy = false) {
        this.popup.clear(isDestroy)
    }

    /** 给节点添加资源条
     * @param parent 目标节点
     */
    async addCurrencyNode(parent: Node) {
        const prefab = await ResLoader.Ins.loadAsync('currency', 'currency', Prefab)
        const battleUI = instantiate(prefab)
        if (!isValid(parent)) return
        battleUI.parent = parent
    }
    // /**
    //  * 缓存中是否存在指定标识的窗口
    //  * @param uiId 窗口唯一标识
    //  * @example
    //  * LayerManager.Ins.has(UIID.loading);
    //  */
    // private has(uiId: number): boolean {
    //     var config = this.configs[uiId];
    //     if (config == null) {
    //         warn(`编号为【${uiId}】的界面配置不存在，配置信息不存在`);
    //         return false;
    //     }

    //     var result = false;
    //     switch (config.layer) {
    //         case LayerType.UI:
    //             result = this.ui.has(config.prefab);
    //             break;
    //         case LayerType.PopUp:
    //             result = this.popup.has(config.prefab);
    //             break;
    //         case LayerType.System:
    //             result = this.system.has(config.prefab);
    //             break;
    //     }
    //     return result;
    // }

    // /**
    //  * 缓存中是否存在指定标识的窗口
    //  * @param uiId 窗口唯一标识
    //  * @example
    //  * LayerManager.Ins.has(UIID.Loading);
    //  */
    // private get(uiId: number): Node {
    //     var config = this.configs[uiId];
    //     if (config == null) {
    //         warn(`编号为【${uiId}】的界面配置不存在，配置信息不存在`);
    //         return null!;
    //     }

    //     var result: Node = null!;
    //     switch (config.layer) {
    //         case LayerType.UI:
    //             result = this.ui.get(config.prefab);
    //             break;
    //         case LayerType.PopUp:
    //             result = this.popup.get(config.prefab);
    //             break;
    //         case LayerType.System:
    //             result = this.system.get(config.prefab);
    //             break;
    //     }
    //     return result;
    // }

    // /**
    //  * 清除所有窗口
    //  * @param isDestroy 移除后是否释放
    //  * @example
    //  * LayerManager.Ins.clear();
    //  */
    // clear(isDestroy: boolean = false) {
    //     this.ui.clear(isDestroy);
    //     this.popup.clear(isDestroy);
    //     this.system.clear(isDestroy);
    // }


    // /**
    //  * 删除一个通过this框架添加进来的节点
    //  * @param node          窗口节点
    //  * @param isDestroy     移除后是否释放资源
    //  * @example
    //  * LayerManager.Ins.removeByNode(cc.Node);
    //  */
    // removeByNode(node: Node, isDestroy?: boolean) {
    //     if (node instanceof Node) {
    //         let comp = node.getComponent(DelegateComponent);
    //         if (comp && comp.vp) {
    //             // 释放显示的界面
    //             if (node.parent) {
    //                 (node.parent as LayerUI).remove(comp.vp.config.prefab, isDestroy);
    //             }
    //             // 释放缓存中的界面
    //             else if (isDestroy) {
    //                 switch (comp.vp.config.layer) {
    //                     case LayerType.UI:
    //                         // @ts-ignore 注：不对外使用
    //                         this.ui.removeCache(comp.vp.config.prefab);
    //                         break;
    //                     case LayerType.PopUp:
    //                         // @ts-ignore 注：不对外使用
    //                         this.popup.removeCache(comp.vp.config.prefab);
    //                         break;
    //                     case LayerType.System:
    //                         // @ts-ignore 注：不对外使用
    //                         this.system.removeCache(comp.vp.config.prefab);
    //                         break;
    //                 }
    //             }
    //         }
    //         else {
    //             warn(`当前删除的node不是通过界面管理器添加到舞台上`);
    //             node.destroy();
    //         }
    //     }
    // }
}